package com.example.demo.util;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.ListBranchCommand;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.transport.CredentialsProvider;
import org.eclipse.jgit.transport.RefSpec;
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
import org.springframework.beans.factory.annotation.Value;

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;

/**
 * java-git工具类
 *
 * @author zhangfc
 * @date 2021/12/30 8:22
 */
@Slf4j
public class JgitUtils {

    private static Git git = null;
    private static String localPath = StrUtil.replace(System.getProperty("user.dir"), "zj-metadata", "");
    @Value("${git.username}")
    private static String userName;
    @Value("${git.password}")
    private static String passWord;
    @Value("${git.project.url}")
    private static String gitUrl;

    public static synchronized void init() throws IOException {
        if (git == null) {
            git = Git.open(new File(localPath, ".git"));
        }
    }

    /**
     * description 克隆仓库代码
     *
     * @return 是否成功
     */
    public static Boolean cloneRepositoryString() {

        String meiiyang = "/bl/meidiyang.git";
        try {
            log.info("JgitUtil.cloneRepository;开始检出Master代码;git路径:{},检出路径:{}", gitUrl + meiiyang, localPath);
            File file = new File(localPath);
            if (file.isDirectory()) {
                //如果目录已经存在则需要删除源文件,重新创建进行覆盖
                log.info("JgitUtil.cloneRepository;该路径:{},已经存在文件,删除原文,进行覆盖,", localPath);
                deleteFile(file);

                //设置Git帐号和密码登录信息
                CredentialsProvider credentialsProvider =
                        new UsernamePasswordCredentialsProvider(userName, passWord);
                //克隆项目到指定路劲
                Git.cloneRepository()
                        .setURI(gitUrl + meiiyang)
                        .setDirectory(new File(localPath))
                        .setCloneAllBranches(true)
                        .setCredentialsProvider(credentialsProvider)
                        .call();
            }
            return true;
        } catch (Exception e) {
            log.error("JgitUtil.cloneReposity;错误,检出Master代码异常;检出路径:{},异常信息:{}", gitUrl + meiiyang, e);
            return false;
        } finally {
            if (git != null) {
                git.close();
            }
        }
    }

    /**
     * description 切换分支
     *
     * @param branchName 要切换的分支
     * @return true 成功  or  false 失败
     */
    public static Boolean checkoutBranch(String branchName) {
        log.info("JgitUtil.checkoutBranch;切换分支;{}", branchName);
        try {
            init();
            CredentialsProvider credentialsProvider =
                    new UsernamePasswordCredentialsProvider(userName, passWord);

            git.checkout()
                    .setCreateBranch(false)
                    .setName(branchName)
                    .call();

            git.pull()
                    .setCredentialsProvider(credentialsProvider)
                    .call();

            return true;

        } catch (Exception e) {
            log.error("JgitUtil.checkoutBranch;错误,切换分支失败;目录:{},异常信息:{}", localPath, e);
            return false;
        } finally {
            if (git != null) {
                git.close();
            }
        }
    }

    /**
     * 更新项目
     *
     * @return 成功 true or 失败 false
     */
    public static Boolean gitPull() {
        log.info("JgitUtil.gitPull;更新代码");
        try {
            init();
            CredentialsProvider credentialsProvider =
                    new UsernamePasswordCredentialsProvider(userName, passWord);

            git.pull()
                    .setCredentialsProvider(credentialsProvider)
                    .setRemoteBranchName("master")
                    .call();
            return true;
        } catch (Exception e) {
            log.error("JgitUtil.gitPull,更新项目异常,信息:{}", e.getMessage(), e);
            return false;
        } finally {
            if (git != null) {
                git.close();
            }
        }
    }

    /**
     * description git添加代码
     *
     * @return 成功 true or 失败 false
     */
    public static Boolean gitAdd() {
        log.info("JgitUtil.gitAdd;添加文件");
        try {
            init();
            git.add()
                    .addFilepattern(".")
                    .call();
            return true;
        } catch (Exception e) {
            log.error("JgitUtil.gitAdd;添加文件失败,信息:{}", e.getMessage(), e);
            return false;
        } finally {
            if (git != null) {
                git.close();
            }
        }
    }

    /**
     * description git提交命令
     *
     * @param commitMessage 提交的信息
     * @return true 成功 or false 失败
     */
    public static Boolean gitCommit(String commitMessage) {
        log.info("JgitUtil.gitCommit;提交代码;信息:{}", commitMessage);
        try {
            init();
            gitPull();
            git.commit()
                    .setMessage(commitMessage)
                    .call();
            return true;
        } catch (Exception e) {
            log.error("JgitUtil.gitCommit;提交代码,出错;信息:{},异常信息", commitMessage, e);
            return false;
        } finally {
            if (git != null) {
                git.close();
            }
        }
    }

    /**
     * description git向远程仓库推送代码
     *
     * @return true 成功  or  false 失败
     */
    public static Boolean gitPush() {
        log.info("JgitUtil.gitPush向远程仓库推送代码");
        try {
            init();
            CredentialsProvider credentialsProvider =
                    new UsernamePasswordCredentialsProvider(userName, passWord);
            //获取当前分支防止向远程仓库推送出错
            String branch = git.getRepository().getBranch();
            git.push()
                    .setCredentialsProvider(credentialsProvider)
                    .call();
            return true;
        } catch (Exception e) {
            log.error("JgitUtil.gitPush向远程代码推送代码出错,错误信息:{}", e.getMessage(), e);
            return false;
        } finally {
            if (git != null) {
                git.close();
            }
        }
    }

    /**
     * description 创建新的分支
     *
     * @param branchName 要创建的分支
     * @return 成功 true or 失败 false
     */
    public static Boolean newBranch(String branchName) {
        try {
            init();
            CredentialsProvider credentialsProvider =
                    new UsernamePasswordCredentialsProvider(userName, passWord);
            //检查新建的分支是否已经存在,如果存在则将已存在的分支强制删除 并 重新创建一个新的分支
            List<Ref> allBranch = git.branchList()
                    .setListMode(ListBranchCommand.ListMode.ALL)
                    .call();
            List<String> brchNameList = allBranch.stream()
                    .map(brach -> brach.getName()
                            .substring(brach.getName().lastIndexOf("/") + 1))
                    .collect(Collectors.toList());
            //如果分支集合包含一个分支则代表分支已经存在
            if (CollUtil.contains(brchNameList, branchName)) {
                log.info("JgitUtil.newBranch;分支已经存在,进行删除再新建:{}", branchName);
                //删除本地分支
                git.branchDelete()
                        .setBranchNames(branchName)
                        //是否强制删除分支
                        .setForce(true)
                        .call();

                RefSpec refSpec = new RefSpec()
                        .setSource(null)
                        .setDestination("refs/heads/" + branchName);
                git.push()
                        .setRefSpecs(refSpec)
                        .setRemote("origin")
                        .setCredentialsProvider(credentialsProvider)
                        .call();
            }
            //新建分支
            Ref ref = git.branchCreate()
                    .setName(branchName)
                    .call();
            git.push()
                    .add(ref)
                    .setCredentialsProvider(credentialsProvider)
                    .call();
            return true;
        } catch (Exception e) {
            log.error("JgitUtil.newBranch;错误;创建新的分支,{}", e.getMessage());
            return false;
        } finally {
            if (git != null) {
                git.close();
            }
        }
    }


    /**
     * 删除文件或文件
     *
     * @param dirFile 要被删除的文件或者文件夹
     * @return 成功true  or  失败false
     */
    private static Boolean deleteFile(File dirFile) {
        //如果dir对应的文件不存在,则退出
        if (!dirFile.exists()) {
            return false;
        }
        //如果是文件的话的直接删除即可
        if (dirFile.isFile()) {
            return dirFile.delete();
        } else if (dirFile.isDirectory()) {
            //如果是目录的话需要进行遍历删除
            File[] files = dirFile.listFiles();
            if (!BeanUtil.isEmpty(files)) {
                for (File file : files) {
                    deleteFile(file);
                }
            }
        }
        return dirFile.delete();
    }

}
